package net.hvacapp.cmvrfforandroid.db.dao;

import android.content.Context;
import android.text.TextUtils;

import com.alibaba.fastjson.JSON;
import com.j256.ormlite.dao.Dao;
import com.j256.ormlite.dao.GenericRawResults;
import com.j256.ormlite.dao.RawRowMapper;
import com.j256.ormlite.field.DataType;
import com.j256.ormlite.stmt.PreparedQuery;
import com.j256.ormlite.stmt.QueryBuilder;
import com.j256.ormlite.stmt.Where;
import com.j256.ormlite.table.TableUtils;

import net.hvacapp.cmvrfforandroid.db.DatabaseHelper;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

/**
 * 基础业务实现类
 *
 * @param <T> <pre>
 *            	文件名: BaseDao<T>.java
 *            </pre>
 *            <p/>
 */
public class BaseDao<T, ID> {
    private static final Logger logger = LoggerFactory.getLogger(BaseDao.class);

    private DatabaseHelper databaseHelper;
    private Dao<T, ID> dao = null;
    private T entity;

    /**
     * 获取T的类型
     */
    @SuppressWarnings("unchecked")
    private Class<T> getT() {
        return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

    public BaseDao(Context context) {
        databaseHelper = DatabaseHelper.getInstance(context);
        try {
            dao = databaseHelper.getDao(getT());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("转换dao失败");
        }
    }

    /**
     * 获取父类Dao的对象
     *
     * @return
     */
    public Dao<T, ID> getBaseDao() {
        return dao;
    }

    /**
     * 保存对象
     *
     * @param t
     * @return T
     */
    public T insertT(T t) {
        if (dao != null) {
            try {
                entity = dao.createIfNotExists(t);
                return entity;
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("{}对象{}保存失败", t.getClass().getSimpleName(), JSON.toJSONString(t));
            }
        }
        return null;
    }

    /**
     * 保存对象
     *
     * @param t
     * @return 结果正确性
     */
    public boolean insert(T t) {
        if (dao != null) {
            try {
                int i = dao.create(t);
                if (i == 1) {
                    return true;
                } else {
                    return false;
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("{}对象{}保存失败", t.getClass().getSimpleName(), JSON.toJSONString(t));
            }
        }
        return false;
    }

    /**
     * 更新对象
     *
     * @param t
     * @return
     */
    public boolean update(T t) {
        if (dao != null) {
            try {
                int i = dao.update(t);
                if (i == 1) {
                    return true;
                } else {
                    return false;
                }
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("{}对象{}更新失败", t.getClass().getSimpleName(), JSON.toJSONString(t));
            }
        }
        return false;
    }

    /**
     * 删除对象
     */
    public boolean delete(T t) {
        if (dao != null) {
            try {
                int rowUpdate = dao.delete(t);
                if (rowUpdate > 0) {
                    return true;
                } else {
                    return false;
                }
            } catch (SQLException e) {
                e.printStackTrace();
                logger.error("{}对象{}删除失败", t.getClass().getSimpleName(), JSON.toJSONString(t));
            }
        }
        return false;
    }

    /**
     * 根据Id删除对象
     *
     * @param id
     */
    public void deleteById(ID id) {
        if (dao != null) {
            try {
                dao.deleteById(id);
            } catch (SQLException e) {
                e.printStackTrace();
                logger.error("{}对象{}删除失败", entity.getClass().getSimpleName(), id);
            }
        }
    }

    /**
     * 清空表
     */
    public void deleteAll() {
        try {
            TableUtils.clearTable(databaseHelper.getConnectionSource(), getT());
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("清空表{}失败", getT().getSimpleName());
        }
    }

    /**
     * 根据主键获取对象
     *
     * @param id
     * @return
     */
    public T get(ID id) {
        try {
            return dao.queryForId(id);
        } catch (Exception e) {
            logger.error("根据主键{}查询出错", id);
        }
        return null;
    }

    /**
     * 获取所有对象
     *
     * @return
     */
    public List<T> getAll() {
        try {
            return dao.queryForAll();
        } catch (Exception e) {
            logger.error("查询失败{}", "getAll");
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 根据条件查询对象集合
     *
     * @param equalFilter
     * @return
     */
    public List<T> find(Map<String, Object> equalFilter) {
        return find(equalFilter, null, null, null, null);
    }

    public List<T> find(Map<String, Object> equalFilter, Map<String, Boolean> order) {
        return find(equalFilter, order, null, null, null);
    }

    /**
     * Or条件查询
     *
     * @param orFilter
     * @param order
     * @return
     */
    public List<T> findOr(Map<String, Object> orFilter, Map<String, Boolean> order) {
        QueryBuilder<T, ID> queryBuilder = dao.queryBuilder();
        try {
            if (orFilter != null && orFilter.size() > 0) {
                Where<T, ID> where = queryBuilder.where();
                for (Entry<String, Object> entry : orFilter.entrySet()) {
                    where.eq(entry.getKey(), entry.getValue());
                }
                where.or(orFilter.size());
            }
            if (order != null && order.size() > 0) {
                for (Entry<String, Boolean> entry : order.entrySet()) {
                    queryBuilder.orderBy(entry.getKey(), entry.getValue());
                }
            }
            // 去除重复记录
            queryBuilder.distinct();
            PreparedQuery<T> preparedQuery = queryBuilder.prepare();
            return dao.query(preparedQuery);
        } catch (Exception e) {
            logger.error("findOr查询出错");
        }
        return null;
    }

    /**
     * 根据条件排序
     *
     * @param order
     * @return
     */
    public List<T> findOrder(Map<String, Boolean> order) {
        QueryBuilder<T, ID> queryBuilder = dao.queryBuilder();
        try {
            if (order != null && order.size() > 0) {
                for (Entry<String, Boolean> entry : order.entrySet()) {
                    queryBuilder.orderBy(entry.getKey(), entry.getValue());
                }
            }
            PreparedQuery<T> preparedQuery = queryBuilder.prepare();
            return dao.query(preparedQuery);
        } catch (Exception e) {
            logger.error("findOrder查询出错");
        }
        return null;
    }

    /**
     * ORM查询
     *
     * @param equalFilter 查询 Map<列名,值>
     * @param order       排序 Map<列名,是否asc>
     * @param groups      分组List<列名>
     * @param startRow    Long类型:从第{startRow}条开始取数据
     * @param maxRows     Long类型:需要取出{maxRows}条数据
     * @return
     */
    public List<T> find(Map<String, Object> equalFilter, Map<String, Boolean> order, List<String> groups, Long startRow, Long maxRows) {
        QueryBuilder<T, ID> queryBuilder = dao.queryBuilder();
        try {
            if (equalFilter != null && equalFilter.size() > 0) {
                Where<T, ID> where = queryBuilder.where();
                for (Entry<String, Object> entry : equalFilter.entrySet()) {
                    where.eq(entry.getKey(), entry.getValue());
                }
                where.and(equalFilter.size());
            }
            if (groups != null && groups.size() > 0) {
                for (String columnName : groups) {
                    queryBuilder.groupBy(columnName);
                }
            }
            if (order != null && order.size() > 0) {
                for (Entry<String, Boolean> entry : order.entrySet()) {
                    queryBuilder.orderBy(entry.getKey(), entry.getValue());
                }
            }
            if (maxRows != null && startRow != null) {
                queryBuilder.offset(startRow).limit(maxRows);
            }
            PreparedQuery<T> preparedQuery = queryBuilder.prepare();
            return dao.query(preparedQuery);
        } catch (SQLException e) {
            logger.error("查询出错");
        }
        return null;
    }

    /**
     * 根据sql语句查询
     *
     * @param sql sql语句
     * @return List<String[]>
     */
    public List<String[]> findStringSql(String sql) {
        if (TextUtils.isEmpty(sql)) {
            return null;
        } else {
            GenericRawResults<String[]> rawResults = null;
            try {
                rawResults = dao.queryRaw(sql);
                return rawResults.getResults();
            } catch (SQLException e) {
                e.printStackTrace();
                return null;
            } finally {
                if (rawResults != null) {
                    try {
                        rawResults.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                        logger.error("关闭rawResult出错");
                    } finally {
                        rawResults = null;
                    }
                }
            }
        }
    }

    /**
     * 根据sql语句查询
     *
     * @param sql sql语句
     * @return List<Object[]>
     */
    public List<Object[]> findObjectSql(String sql) {
        if (TextUtils.isEmpty(sql)) {
            return null;
        } else {
            GenericRawResults<Object[]> rawResults = null;
            try {
                rawResults = dao.queryRaw(sql, new DataType[]{DataType.INTEGER});
                return rawResults.getResults();
            } catch (SQLException e) {
                e.printStackTrace();
                return null;
            } finally {
                if (rawResults != null) {
                    try {
                        rawResults.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                        logger.error("关闭rawResult出错");
                    } finally {
                        rawResults = null;
                    }
                }
            }
        }
    }

    /**
     * 根据sql语句查询
     *
     * @param sql       sql语句
     * @param rowMapper RawRowMapper<T>接口,需重写
     * @return List<T>
     */
    public List<T> findTSql(String sql, RawRowMapper<T> rowMapper) {
        if (TextUtils.isEmpty(sql)) {
            return null;
        } else {
            GenericRawResults<T> rawResults = null;
            try {
                rawResults = dao.queryRaw(sql, rowMapper);
                return rawResults.getResults();
            } catch (SQLException e) {
                return null;
            } finally {
                if (rawResults != null) {
                    try {
                        rawResults.close();
                    } catch (SQLException e) {
                        logger.error("关闭rawResult出错");
                    } finally {
                        rawResults = null;
                    }
                }
            }
        }
    }

    /**
     * 根据sql语句查询总数
     *
     * @param sql
     * @return count(*)
     */
    public int queryCount(String sql) {
        try {
            GenericRawResults<String[]> rawResults = dao.queryRaw(sql);
            List<String[]> results = rawResults.getResults();
            String[] resultArray = results.get(0);
            return Integer.valueOf(resultArray[0]);
        } catch (SQLException e) {
            e.printStackTrace();
            logger.error("根据sql语句{}查询总数出错", sql);
        }
        return 0;
    }

    /**
     * 数据库更新
     *
     * @param sql 原生的Sql语句(必须包含关键字INSERT,、DELETE、 UPDATE)
     */
    public void updateRawSql(String sql) {
        if (dao != null) {
            try {
                dao.updateRaw(sql);
            } catch (Exception e) {
                logger.error("执行{}失败", sql);
            }
        }
    }
}
